package 函数式编程;

import java.util.Comparator;
import java.util.Objects;
import java.util.function.BiFunction;

import 泛型.extends通配符;
/*
public class Lambda表达式 {

}
文章目录
1、Lambda表达式概述
2、Lambda表达式语法
3、具体写法
     无返回值有形参的抽象方法
     有返回值的抽象方法
     一个形参的抽象方法
     Lambda表达式作为参数传递
4、Lambda表达式注意事项
5、Java中四大函数式接口
6、方法引用
     对象::实例方法
     类::静态方法
     类::实例方法
7、构造引用

1、Lambda表达式概述
Lambda表达式是JDK1.8之后的一种语法，是一个匿名函数，是对匿名函数的简写形式，我们可以把 Lambda表达式理解为是一段可以传递的代
码（将代码像数据一样进行传递），可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格，使Java的语言表达能力得到了提升；

首先来看一下什么是Lambda表达式：
*/
/*import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
String
public class Lambda表达式 {
    public static void main(String[] args) {
        Integer[] ints = {98, 243, 35, 13, 57, 243};
        List<Integer> list = Arrays.asList(ints);//数组转换成列表
        
        System.out.println(Arrays.toString(ints));//[98, 243, 35, 13, 57, 243]
        System.out.println(list);//[98, 243, 35, 13, 57, 243]
        
        list.sort(new Comparator<Integer>() {//void java.util.List.sort(Comparator<? super Integer> c)
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2-o1;
            }
        });
        System.out.println(list); //[243, 243, 98, 57, 35, 13]

        //使用Lambda表达式
//        void java.util.List.sort(Comparator<? super Integer> c)
        list.sort((o1,o2)->(o1-o2));
        System.out.println(list); //[13, 35, 57, 98, 243, 243]
    }
}*/

/*
通过上面的对比，发现Lambda表达式式书写起来更为简洁；

2、Lambda表达式语法
JDK1.8之后引入的一种语法，他的写法是使用一个->符号，箭头将Lambda表达式分为左右两部分，左边写的是实现的这个接口中的抽象方法中的
形参列表，右边就是对抽象方法的处理；

实现的这个接口中的抽象方法中的 “形参列表 -> 抽象方法的处理”

3、具体写法
因为Lambda表达式的核心就是实现的这个接口中的抽象方法中的 “形参列表 -> 抽象方法的处理”，因此根据形参列表与返回值的不同，Lambda表达式
的具体写法也不相同；

一.《无返回值有形参的抽象方法》

 */
/*
public class Lambda表达式 {
    public static void main(String[] args) {
        MyInterface<Integer> myInterface = new MyInterface<>() {
            @Override
            public void show(Integer a,Integer b) {
                System.out.println(a + b);
            }
        };

        myInterface.show(20, 30);//50

        //简写1：匿名show,大括号内为覆写接口MyInterface之抽象方法show的语句，方法名可以自己推断出来
        MyInterface<Float> myInterface1 = (Float a,Float b) -> {
            System.out.println(a + b);
        };

        myInterface1.show(20f, 40f);//60

        //简写2：可以省略形参列表中的形参类型
        MyInterface<Double> myInterface2 = (a, b) -> {
            System.out.println(a + b);//70
        };

        myInterface2.show(20d, 50d);

        //简写3：如果抽象方法中只有一行代码，可以省略方法体的大括号，当然，如果不止一行，就不能省略
        MyInterface<Integer> myInterface3 = (a, b) -> System.out.println(a + b);
        myInterface3.show(20, 60);//80
    }
}

interface MyInterface<T extends Number> {
//    public abstract void show(int a,int b);
    void show(T a,T b);//亦可
}
*/
//可以省略方法名，IDEA会帮你自动检测方法名；
//可以省略方法中的形参类型；
//如果对抽象方法的实现逻辑只有一行，可以省略方法体的大括号，当然如果不止一行，就不能省略了；

//二.《有返回值的抽象方法》
/*
public class Lambda表达式 {
    public static void main(String[] args) {
        MyInterface1 test1 = new MyInterface1() {
            @Override
            public int test(int a, int b) {
                return a - b;
            }
        };
        System.out.println(test1.test(90, 8));//82

        //简写1：
        MyInterface1 test2 = (int a, int b) -> {
            return a - b;
        };
        System.out.println(test2.test(20, 10));//10

        //简写2：
        MyInterface1 test3 = (a, b) -> {return a - b;};
        System.out.println(test3.test(30, 10));//20

        //简写3：这个有返回值的方法，不能直接去掉大括号，还需要去掉return关键字
        MyInterface1 test4 = (a, b) -> a - b;
        System.out.println(test4.test(40, 10));//30
    }
}

interface MyInterface1 {
    public abstract int test(int a,int b);
}
//有返回值的方法，如果要去掉大括号，还需要去掉return关键字；
*/
//三.《有一个形参的抽象方法》
/*public class Lambda表达式 {
    public static void main(String[] args) {
        MyInterface2 myInterface = a -> a-20;//形参列表中只有一个参数，可以去掉形参的括号；
        System.out.println(myInterface.show(220));//200
    }
}

interface MyInterface2 {
    public abstract int show(int a);
}*/

//四.《Lambda表达式作为参数传递》
/*import java.util.Arrays;
public class Lambda表达式 {
    public static void main(String[] args) {
        Integer[] ints = {89, 67, 23};
//        <Integer> void java.util.Arrays.sort(Integer[] a, Comparator<? super Integer> c)
        Arrays.sort(ints, (o1, o2) -> o1-o2);//(o1, o2) -> o1-o2作为参数
        System.out.println(Arrays.toString(ints));
        //[23, 67, 89]
    }
}*/
//Lambda表达式也可以作为参数传递；
//
//4、Lambda表达式注意事项
//Lambda表达式不是万能的，他需要函数式接口的支持；
//函数式接口的定义是: 只包含一个抽象方法的接口，称为函数式接口；
//其实我们的Lambda表达式就是对函数式接口的一种简写方式，所以只要是函数式接口，我们才能用Lambda表达式；再换句话说，Lambda表达式
//需要函数式接口的支持，那函数式接口我们可以自己定义，当然JDK1.8也给我们提供了一些现成的函数式接口；
//
//自定义一个函数式接口
//@FunctionalInterface //注解用来表明这是一个函数式接口
//public interface MyInterFace<T>{
//	//函数式接口只能有一个抽象方法
//	void getValue(T t);
//}
//自定义的函数式接口的Lambda表达式：
//MyInterFace<String> face=(x)->System.out.println(x);

//●可以通过 Lambda 表达式来创建该接口的对象，我们可以在任意函数式接口上使用@FunctionalInterface 注解，这样做可以检查它是否是一个函数式接口；
//●为什么只能有一个抽象方法，如果有多个抽象方法，这个接口不是函数式接口，简写的时候省略了方法名，IDEA不能知道到底重写的是哪一个方法，不能推断出来；
//●注解写在接口声明上面，如果不报错，就不是函数式接口；？
//●JDK1.8之后，提供了很多函数式接口，作为参数传递；
//
//5、Java中四大函数式接口
//┌─────────────────────────┬────────────┬─────────────┬─────────────────────────────────────────────────────────────┐
//│        函数式接口。        │    参数类型  │  返回类型     │                    用     途                                │
//├─────────────────────────┼────────────┼─────────────┼─────────────────────────────────────────────────────────────┤
//│ Consumer<T>：   消费型接口 │     T      │   void      │ 对类型为T的对象应用操作包含方法：void accept(T t)                   │
//├─────────────────────────┼────────────┼─────────────┼─────────────────────────────────────────────────────────────┤
//│ Supplier<T>：   供给型接口 │     无：    │     T       │ 返回类型为T的对象,包含方法:T get()                                │ 
//├─────────────────────────┼────────────┼─────────────┼─────────────────────────────────────────────────────────────┤
//│ Function<T,R>： 函数型接口 │     T      │     R       │ 对类型为T的对象应用操作，并返回R类型的对象,包括方法: R apply(T t)       │
//├─────────────────────────┼────────────┼─────────────┼─────────────────────────────────────────────────────────────┤
//│ Predicate<T>：  断言型接口 │     T      │   boolean   │确定类型为T的对象是否满足某约束并返回boolean值，包括方法boolean test(T t)│
//└─────────────────────────┴────────────┴─────────────┴─────────────────────────────────────────────────────────────┘
//┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
//│        函数式接口                 参数类型   返回的类型                          用   途                                 │
//├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
//│ BiFunction<T U R>                T U       R      对类型为T U的对象应用操作,并返回R类型的对象,包括方法:R apply(T t，U u)     │
//│ UnaryOperator<T>：Function子接口    T         T      对类型为T的对象进行一元运算，返回T类型结果,包括方法:T apply(T t)          │
//│ BinaryOperator<T>：BiFunction子接口 T T       T      对类型为T的对象进行二元运算,返回T类型结果，包括方法:T apply(T t1,T t2)    │
//│ BiConsumer<T,U>                  T U     void     对类型为T,U参数应用操作,包含方法:void accept(T t,U u)                 │
//│ BiPredicate<T, U>                T U     boolean  接收一个T,U类型的参数，返回一个boolean类型的结果:boolean test(T t，U u)  │
//│ ToIntFunction<T>                 T       int      计算int值的函数           int applyAsInt(T value)                 │
//│ ToLongFunction<T>                T       long     计算long值的函数                                                  │
//│ ToDoubleFunction<T>              T       double   计算double值的函数                                                │
//│ IntFunction<R>                   int       R      参数为int类型的函数         R apply(int value)                     │
//│ LongFunction<R>                  long      R      参数为long类型的函数                                               │
//│ DoubleFunction<R>                double    R      参数为double类型的函数                                             │
//└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
//
//┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
//│        函数式接口       参数类型   返回类型                                用 ， 途                                     │
//├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
//│Comparator<T> 比较器接口    T    int   对类型为T的对象应用操作包含方法:int compare(T o1,T o2); -1:o1<o2; 0:o1=o2; 1:o1>o2  │ 
//└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

//6、方法引用
//先来看一下什么是方法引用：
//
//方法引用其实是Lambda表达式的另一种写法，当要传递给Lambda体的操作，已经有实现的方法了，可以使用方法引用；
//注意： 实现抽象方法的参数列表，必须与方法引用方法的参数列表保持一致！
//方法引用：使用操作符::将方法名和对象或类的名字分隔开来，三种主要使用情况为：
//
// 1.   对象::实例方法
// 2.    类::静态方法
// 3.    类::实例方法
//
//1.《对象::实例方法》
/*
import java.util.function.Consumer;
public class Lambda表达式 {
    public static void main(String[] args) {
        Consumer<String> consumer = new Consumer<String>() {//java.util.function.Consumer<String>
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        consumer.accept("aaaaaaaaaaaaaa");

        //简写1：
        Consumer<String> consumer1 = (String s) -> {
            System.out.println(s);
        };
        consumer1.accept("abc");
        //abc

        //简写2：
        //Consumer<String> consumer2 = s -> System.out.println(s);//亦可
        Consumer<String> consumer2 = (s) -> System.out.println(s);
        consumer2.accept("bcd");
        //bcd

        //简写3：
        Consumer<String> consumer3 = System.out::println;//静态方法引用，
        consumer3.accept("abc");
        //abc
    }
}*/
//
//为什么可以写成上述方式？
//因为：System.out.println(s);与void accept(String s)一样，都是使用s作为参数，返回值是void，(形参和返回类型一致)，因此就可以简写为简写3；
//
//2.《类::静态方法》
/*
import java.util.function.BinaryOperator;
public class Lambda表达式 {
    public static void main(String[] args) {
 
//    	@FunctionalInterface
//    	public interface BiFunction<T, U, R> {//BinaryOperator的父类
//    	    R apply(T t, U u);
//    	}

//    	@FunctionalInterface
//    	public interface BinaryOperator<T> extends BiFunction<T,T,T> {
//
//    	    public static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) {
//    	        Objects.requireNonNull(comparator);
//    	        return (a, b) -> comparator.compare(a, b) <= 0 ? a : b;
//    	    }
//
//    	    public static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) {
//    	        Objects.requireNonNull(comparator);
//    	        return (a, b) -> comparator.compare(a, b) >= 0 ? a : b;
//    	    }
//    	}
    	
        //BinaryOperator<Double> operator = new BinaryOperator<>(){
      	  //BinaryOperator<Double> operator = new BinaryOperator<>(){
        BiFunction<Double,Double,Double> operator = new BiFunction<>(){//亦可,BiFunction<T,T,R> -> BiFunction<T,T,T>
            @Override  //覆写父类BiFunction<T, U, T>的抽象方法：
            public Double apply(Double o, Double o2) {
                return Math.max(o,o2);//静态方法
            }
        };
        System.out.println(operator.apply(2.13, 3.12));//3.12

        BinaryOperator<Double> operator2 = (o, o2) -> Math.max(o,o2);
        System.out.println(operator2.apply(2.13, 3.12));//3.12

        BinaryOperator<Double> operator3 = Math::max;//double java.lang.Math.max(double a, double b)
        Double max = operator3.apply(5.0, 20.0);
        System.out.println(max);//20.0

        BinaryOperator<Double> operator4=(a, b) -> Double.compare(a, b) <= 0 ? a : b; //minBy
        BinaryOperator<Double> operator5=new BinaryOperator<>() {
        	public Double apply(Double a,Double b) {
        		return Double.compare(a, b) <= 0 ? a : b; //minBy
        	}
        };
        Double min=operator4.apply(2.13,3.12);
        System.out.println(min);
        Double min1=operator5.apply(2.13,3.12);
        System.out.println(min1);

    }
}
*/
//Math.max():double java.lang.Math.max(double a, double b)
//operator.apply():Double apply(Double o, Double o2)
//所需要的参数以及返回值与重写的一样，因此可以简写为类::静态方法；
//
import java.util.Comparator;
public class Lambda表达式 {
    public static void main(String[] args) {
   	 
       //public final class Integer extends Number implements Comparable<Integer>, Constable, ConstantDesc {
       //      //Integer类静态方法
   	 //      public static int compare(int x, int y) {
       //            return (x < y) ? -1 : ((x == y) ? 0 : 1);
       //            }
       //      }

   	 //@FunctionalInterface
   	 //public interface Comparator<T> {
   	 //    int compare(T o1, T o2);
   	 //    ...
   	 //}
        Comparator<Integer> comparator = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o1,o2);//调用Integer类静态方法
            }
        };

        System.out.println(comparator.compare(20, 12));//1
        //Integer类静态方法compareTo (compare(this.value, anotherInteger.value))与Comoarator接口方法compare形参及返回类型一致，可直接互换使用
        Comparator<Integer> comparator1 = Integer::compareTo;
        System.out.println(comparator1.compare(20, 12));//1
        //Integer类静态方法compare与Comoarator接口方法compare形参及返回类型一致，可直接互换使用
        Comparator<Integer> comparator2 = Integer::compare;
        System.out.println(comparator2.compare(20, 12));//1
        
    }
}
//
//3.《类::实例方法》
/*import java.util.Comparator;
public class Lambda表达式 {
    public static void main(String[] args) {
        Comparator<String> comparator = new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
            	//int java.lang.String.compareTo(String anotherString)为实例方法
                return o1.compareTo(o2);
            }
        };

        System.out.println(comparator.compare("20", "12"));//1

        Comparator<String> comparator1 = String::compareTo;
        System.out.println(comparator1.compare("20", "12"));//1
    }
}*/

//为什么可以这样写？、
//传递过来的两个参数，一个作为调用者(o1)，一个作为参数(o2)，这时候，使用类::实例方法简写；
//
//7、构造引用
//格式：ClassName::new
//与函数式接口相结合，自动与函数式接口中方法兼容。可以把构造器引用赋值给定义的方法，与构造器参数列表要与接口中抽象方法的参数列表一致！

//import java.util.function.BiFunction;
//import java.util.function.Supplier;
///*public class Lambda表达式 {
//    public static void main(String[] args) {
//        Supplier<Student> supplier = new Supplier<Student>() {
//            @Override
//            public Student get() {
//                return new Student();
//            }
//        };
//
//        Student student = supplier.get();
//        System.out.println(student);
//
//        Supplier<Student> supplier1 = () -> new Student();
//        Student student1 = supplier1.get();
//        System.out.println(student1);
//    }
//}*/
//
/*
class Student{
	private String name;
	private int age;
	public Student(String name,int age) {
		this.name=name;
		this.age=age;
	}
	@Override
	public String toString() {
        return "姓名："+this.name+"   年龄："+this.age;
	}
}
//
//public class Lambda表达式 {
//    public static void main(String[] args) {
//        Supplier<Student> supplier1 = new Supplier<Student>() {
//            @Override
//            public Student get() {
//                return new Student("张三",23);
//            }
//        };
//
//        Student student1 = supplier1.get();
//        System.out.println(student1);
//
//        Supplier<Student> supplier2 = () -> new Student("李四",25);
//        Student student2 = supplier2.get();
//        System.out.println(student2);
//    }
//}

public class Lambda表达式 {
    public static void main(String[] args) {
        Student student = new Student("张三", 23);
        
//    	@FunctionalInterface
//    	public interface BiFunction<T, U, R> {//BinaryOperator的父类
//    	    R apply(T t, U u);
//    	}
        
        BiFunction<String, Integer, Student> function = new BiFunction<String, Integer, Student>() {
            @Override
            public Student apply(String s, Integer integer) {
//                return student;
                return new Student(s,integer);//亦可
            }
        };
        System.out.println(function.apply("李四", 38));

//        BiFunction<String, Integer, Student> function1 = (s, integer) -> student;
        BiFunction<String, Integer, Student> function1 = (s, integer) -> new Student(s,integer);
        System.out.println(function1.apply("李四", 38));
        
        BiFunction<String, Integer, Student> function2 = Student::new;
        System.out.println(function2.apply("李四", 38));
    }
}
*/
//之所以可以这样简写，是因为构造方法的形参与返回值与重写的方法一样；
